/****************************************************************************
*
* Copyright (c) 2023  C*Core -   All Rights Reserved
*
* THIS SOFTWARE IS DISTRIBUTED "AS IS, " AND ALL WARRANTIES ARE DISCLAIMED,
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* PROJECT     : CCFC2011BC
* DESCRIPTION : CCFC2011BC LIN low level drivers code
* HISTORY     : CCFC2011BC
* @file     lin_lin.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#include "CCFC2011BC.h"
#include "lin_lld.h"
#include "console.h"
#include "IntcInterrupts.h"
#include "intc_lld.h"
#include "edma_lld.h"

/**
 * @brief   Driver default configuration.
 */
static const LinConfig default_config = {
    LIN_DEFAULT_BAUDRATE,
    LIN_MODE_MASTER,
    CCFC20xx_LIN_API_MODE_SYNCHRONOUS,
    NULL,
    NULL,
    NULL,
    NULL,
    0,
    0,
    NULL
};

/**
 * @brief   LIINFlex - 0 lin driver identifier.
 */
#if (CCFC20xx_LINFLEX0_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD1;
#endif

/**
 * @brief   LIINFlex - 1 lin driver identifier.
 */
#if (CCFC20xx_LINFLEX1_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD2;
#endif

/**
 * @brief   LIINFlex - 2 lin driver identifier.
 */
#if (CCFC20xx_LINFLEX2_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD3;
#endif

/** LIINFlex - 3 LIN driver identifier **/
#if (CCFC20xx_LINFLEX3_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD4;
#endif

/** LIINFlex - 4 LIN driver identifier **/
#if (CCFC20xx_LINFLEX4_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD5;
#endif

/** LIINFlex - 5 LIN driver identifier **/
#if (CCFC20xx_LINFLEX5_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD6;
#endif

/** LIINFlex - 6 LIN driver identifier **/
#if (CCFC20xx_LINFLEX6_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD7;
#endif

/**    LIINFlex - 7 LIN driver identifier **/
#if (CCFC20xx_LINFLEX7_SETTING == CCFC20xx_LINFLEX_MODE_LIN) || defined(__DOXYGEN__)
LinDriver LD8;
#endif

/*===========================================================================*/

/**
 * @brief   LIINFlex - 0 serial driver identifier.
 */
#if (CCFC20xx_LINFLEX0_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD1;
#endif

/**
 * @brief   LIINFlex - 1 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX1_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD2;
#endif

/**
 * @brief   LIINFlex - 2 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX2_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD3;
#endif

/**
 * @brief   LIINFlex - 3 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX3_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD4;
#endif

/**
 * @brief   LIINFlex - 4 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX4_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD5;
#endif

/**
 * @brief   LIINFlex - 5 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX5_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD6;
#endif

/**
 * @brief   LIINFlex - 6 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX6_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD7;
#endif

/**
 * @brief   LIINFlex - 7 serial driver identifier.
*/
#if (CCFC20xx_LINFLEX7_SETTING != CCFC20xx_LINFLEX_MODE_NONE) || defined(__DOXYGEN__)
static LinflexDriver LinflexD8;
#endif

/*******************************************************************************
 * @brief      This function shall be set filter  .
 * @param[in]  LinDriver *ldp, uint32_t filter, LinFilter *filter_cfg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void CCFC20xx_linflex_set_filter(const LinDriver *ldp, uint32_t filter, const LinFilter *filter_cfg)
{
    uint32_t ifcrx_off;
    uint16_t ifer;
    uint8_t ifmr;
    uint32_t *pFilter;
    uint32_t p;

    ifcrx_off = (((filter * 4U) + CCFC20xx_LINFLEX_IFCR0_OFFSET) / 4U);
    p = (uint32_t) (ldp->linflexlp);

    p += ifcrx_off * sizeof (uint32_t);
    pFilter = (uint32_t *)p;

    ifer = (uint16_t)(ldp->linflexlp->IFER.R & 0xFFFFU);
    ldp->linflexlp->IFER.R = (uint16_t) (ifer | (((uint32_t)1U << filter))); /* Enable #Filter */

    *pFilter = (((((uint32_t)filter_cfg->datasize - 1U) & CCFC20xx_BIDR_DFL_MASK) << 10U) |  \
             ((uint32_t)filter_cfg->direction << 9U) | ((uint32_t)filter_cfg->ccs << 8U) |   \
              ((uint32_t)filter_cfg->value & CCFC20xx_BIDR_ID_MASK));

    if (filter_cfg->mode == LIN_MASK_MODE)
    {
    ifmr = (uint8_t)(ldp->linflexlp->IFMR.R & 0xFFU);                  /* Filter 2n and 2n + 1 are in mask mode. */
    ldp->linflexlp->IFMR.R = (uint16_t) (ifmr | (((uint32_t)1U << (filter >> 1)))); /* Set the Mode Register.  */

    pFilter++;                                                         /* Now pFilter->Filter2n + 1            */

    *pFilter = ((uint32_t)filter_cfg->mask_value & CCFC20xx_BIDR_ID_MASK); /* Set the Mask value for filter 2n + 1.  */
    }
}

/*******************************************************************************
 * @brief      This function shall be the LIN mode INIT.
 * @param[in]  LinDriver *ldp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Linflex_Start(const LinDriver *ldp)
{
    uint32_t i = 0;
     volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)ldp->config->mode;  /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;         /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;         /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 0;
    linflexlp->LINCR2.B.IOBE = 0;         /* Bit Error does not reset LIN state machine */
    linflexlp->LINTCSR.B.LTOM = 0;        /* LIN timeout mode for 8 - bit counter */
    linflexlp->LINTCSR.B.IOT  = 0;        /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;        /* Time - out counter enable - OCF flag is set if an output compare event occurs */

    linflexlp->LINSR.R = 0xFFFF;          /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;              /* LIN Interrupts disabled.     */

    /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F =  LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M =  LIN_DIV_M;

    if (ldp->config->tx_end_cb != NULL)
    {
          /* Enable Header transmit interrupt */
        ldp->linflexlp->LINIER.B.HRIE = 1;
    }

    if (ldp->config->rx_end_cb != NULL)
    {
    /* Enable receive interrupt */
        ldp->linflexlp->LINIER.B.DRIE = 1;
    }

    if ((ldp->config->mode == LIN_MODE_SLAVE) && (ldp->config->filters != NULL) && (&CCFC20xx_LINFLEX0L == linflexlp))
    {
        while (i < LIN_NUM_FILTERS)
        {
            LinFilter const *p = ldp->config->filters[i];
            if (p != NULL)
            {
                CCFC20xx_linflex_set_filter(ldp, i, p);
                if (p->mode == LIN_MASK_MODE)
                { /* The filter 2n is in Mask mode, then skip the next one because the */
                    i += 1U;                        /* Mask value has been already set in filter 2n + 1.                   */
                }
            }
            i += 1U;
        }
    }
    else if ((ldp->config->mode == LIN_MODE_SLAVE) && (&CCFC20xx_LINFLEX0L != linflexlp))
    {
        linflexlp->LINCR1.B.BF = 1;
    }
    else
    {
        /** No code **/
    }

    /* Leaves the configuration mode.*/
    linflexlp->LINCR1.B.INIT = 0;  /* Enter in normal mode */
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX0_RXI_IRQ_HANDLER.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX0_RXI_IRQ_HANDLER(void)
{
    LinflexD1.rxi_lincallback(LinflexD1.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX0_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX0_TXI_IRQ_HANDLER(void)
{
    LinflexD1.txi_lincallback(LinflexD1.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX0_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX0_ERR_IRQ_HANDLER(void)
{
    LinflexD1.err_lincallback(LinflexD1.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX1_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX1_RXI_IRQ_HANDLER(void)
{
    LinflexD2.rxi_lincallback(LinflexD2.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX1_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX1_TXI_IRQ_HANDLER(void)
{
    LinflexD2.txi_lincallback(LinflexD2.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX1_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX1_ERR_IRQ_HANDLER(void)
{
    LinflexD2.err_lincallback(LinflexD2.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX2_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX2_RXI_IRQ_HANDLER(void)
{
    LinflexD3.rxi_lincallback(LinflexD3.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX2_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX2_TXI_IRQ_HANDLER(void)
{
    LinflexD3.txi_lincallback(LinflexD3.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX2_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX2_ERR_IRQ_HANDLER(void)
{
    LinflexD3.err_lincallback(LinflexD3.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX3_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX3_RXI_IRQ_HANDLER(void)
{
    LinflexD4.rxi_lincallback(LinflexD4.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX3_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX3_TXI_IRQ_HANDLER(void)
{
    LinflexD4.txi_lincallback(LinflexD4.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX3_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX3_ERR_IRQ_HANDLER(void)
{
    LinflexD4.err_lincallback(LinflexD4.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX4_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX4_RXI_IRQ_HANDLER(void)
{
    LinflexD5.rxi_lincallback(LinflexD5.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX4_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX4_TXI_IRQ_HANDLER(void)
{
    LinflexD5.txi_lincallback(LinflexD5.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX4_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX4_ERR_IRQ_HANDLER(void)
{
    LinflexD5.err_lincallback(LinflexD5.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX5_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX5_RXI_IRQ_HANDLER(void)
{
    LinflexD6.rxi_lincallback(LinflexD6.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX5_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX5_TXI_IRQ_HANDLER(void)
{
    LinflexD6.txi_lincallback(LinflexD6.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX5_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX5_ERR_IRQ_HANDLER(void)
{
    LinflexD6.err_lincallback(LinflexD6.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX6_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX6_RXI_IRQ_HANDLER(void)
{
    LinflexD7.rxi_lincallback(LinflexD7.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX6_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX6_TXI_IRQ_HANDLER(void)
{
    LinflexD7.txi_lincallback(LinflexD7.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX6_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX6_ERR_IRQ_HANDLER(void)
{
    LinflexD7.err_lincallback(LinflexD7.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX7_RXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX7_RXI_IRQ_HANDLER(void)
{
    LinflexD8.rxi_lincallback(LinflexD8.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX7_TXI_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX7_TXI_IRQ_HANDLER(void)
{
    LinflexD8.txi_lincallback(LinflexD8.device);
}

/*******************************************************************************
 * @brief      This function shall be the LINFLEX7_ERR_IRQ_HANDLER.
 * @param[in]  void
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFLEX7_ERR_IRQ_HANDLER(void)
{
    LinflexD8.err_lincallback(LinflexD8.device);
}

/*******************************************************************************
 * @brief      This function shall be the transmit buffer into register.
 * @param[in]  LinDriver *ldp, uint8_t *tx_buf, uint32_t len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ld_txi(const LinDriver *ldp, const uint8_t *tx_buf, uint32_t len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    t_Data tData;
    uint8_t gtFour = 0;
    uint16_t i, max_index = 3U;
    uint32_t len_temp = len;
    uint8_t const *ptemp = tx_buf;

    while (len_temp > 0U)
    {
        /* Clean temporary buffer before transmit data. */
        for (i = 0; i < 4U; i++)
        {
            tData.b[i] = 0;
        }

        /* Fill temporary buffer with the characters to transmit (tx_buf). */
        for (i = 0; ((i < len_temp) && (i < 4U)); i++)
        {
            tData.b[max_index - i] = *ptemp;
            ptemp++;
        }

        /* Transfer temporary buffer to Buffer Data Register. */
        if (gtFour == 0U)
        {
            linflexlp->BDRL.R =  tData.w;
            gtFour = 1;
        }
        else
        {
            linflexlp->BDRM.R =  tData.w;
        }

        if (len_temp < 4U)
        {
            len_temp = 0U;
        }
        else
        {
            len_temp -= 4U;
        }
    }
}

/*******************************************************************************
 * @brief      LINFlex_TXI_IRQHandler
 * @param[in]  uint32_t ildp
 * @param[out] None
 * @retval     None
 * @notapi
*******************************************************************************/
static void LINFlex_TXI_IRQHandler(uint32_t ildp)
{
    uint32_t status;
    int32_t temp;
    LinDriver *ldp = (LinDriver *)ildp;

    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    status = linflexlp->LINSR.R;

    if ((status & CCFC20xx_LINSR_HRF) != 0U)
    {
        /* Slaver transmit mode */
        /* Call the related callback.
         * tx_buf will be filled by this callback
         */
        if (ldp->config->dma_enable == 1u)
        {
            temp = (int32_t)ldp->rx_len;
            temp = - temp;
            EdmaChannelSetup_C(0, (vuint32_t)ldp->tx_buf, (vuint32_t)&LINFLEX_0.BDRL, 4, 4, 2, 2,  \
                              (uint8_t)ldp->tx_len, 1, temp, (int32_t)ldp->tx_len, 0);
            EDMA.TCD[0].START = 1;  /* PRQA S 0662*/                       /** Initialize status flags **/
        }
        else
        {
            ld_txi(ldp, ldp->tx_buf, ldp->tx_len);
        }

        /* Trigger Data transmissi on*/
        linflexlp->LINCR2.B.DTRQ = 1;
        linflexlp->LINSR.B.HRF = 1;
    }
    else
    {
        /* Master transmit mode */

        /* Acknowledge transmit interrupt */
        linflexlp->LINSR.B.DTF = 1;

        /* Disable transmit interrupt */
        linflexlp->LINIER.B.DTIE = 0;

        CCFC20xx_LIN_TX_DONE(ldp);
    }
}

/*******************************************************************************
 * @brief      This function shall be the receive data from register.
 * @param[in]  LinDriver *ldp, uint8_t *tx_buf, uint32_t len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ld_rxi(const LinDriver *ldp, uint8_t *rx_buf, uint32_t len)
{
    volatile struct CCFC20xxbc_linflexl const *linflexlp = ldp->linflexlp;
    uint8_t gtFour = 0;
    uint16_t i, max_index = 3U;
    t_Data tData;
    uint32_t len_temp = len;
    uint8_t *ptemp = rx_buf;

    while (len_temp > 0U)
    {
        /* Clean temporary buffer before to receive data. */
        for (i = 0; i < 4U; i++)
        {
            tData.b[i] = 0;
        }

        /* Transfer Buffer Data Register to temporary data. */
        if (gtFour == 0U)
        {
            tData.w = linflexlp->BDRL.R;
            gtFour = 1;
        }
        else
        {
            tData.w = linflexlp->BDRM.R;
        }

        /* Fill RX buffer (rx_buf) from temporary data buffer with the character to receive. */
        for (i = 0; ((i < len) && (i < 4U)); i++)
        {
            *ptemp = tData.b[max_index - i];    /* Endianess to take in account */
            ptemp++;
        }

        if (len_temp < 4U)
        {
            len_temp = 0U;
        }
        else
        {
            len_temp -= 4U;
        }
    }
}

/*******************************************************************************
 * @brief      Lin_Txi_DMA
 * @param[in]  uint32_t *dma_buf, uint8_t *tx_buf, uint32_t len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Lin_Txi_DMA(uint32_t *dma_buf, const uint8_t *tx_buf, uint32_t len)
{
    uint8_t gtFour = 0;
    uint16_t i, max_index = 3U;
    t_Data tData;
    uint32_t len_temp = len;
    uint8_t const *ptemp = tx_buf;

    while (len_temp > 0U)
    {
        /* Clean temporary buffer before transmit data. */
        for (i = 0; i < 4U; i++)
        {
            tData.b[i] = 0;
        }

        /* Fill temporary buffer with the characters to transmit (tx_buf). */
        for (i = 0; ((i < len_temp) && (i < 4U)); i++)
        {
            tData.b[max_index - i] = *ptemp;
            ptemp++;
        }

        /* Transfer temporary buffer to Buffer Data Register. */
        if (gtFour == 0U)
        {
            dma_buf[0] = tData.w;
            gtFour = 1;
        }
        else
        {
            dma_buf[1] = tData.w;
        }

        if (len_temp < 4U)
        {
            len_temp = 0U;
        }
        else
        {
            len_temp -= 4U;
        }
    }
}

/*******************************************************************************
 * @brief      LINFlex_RXI_IRQHandler
 * @param[in]  uint32_t ildp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFlex_RXI_IRQHandler(uint32_t ildp)
{
    LinDriver *ldp = (LinDriver *)(ildp);
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    uint16_t len;
    int32_t temp;
    if ((linflexlp->LINSR.R & CCFC20xx_LINSR_HRF) != 0U)
    {
        if ((ldp->config->filters == NULL) && (ldp->config->nofilter != NULL))
        {
            linflexlp->BIDR.B.CCS = (uint8_t)ldp->config->nofilter->ccs;
            linflexlp->BIDR.B.DFL = (uint8_t)((uint8_t)ldp->config->nofilter->datasize - 1u);
            linflexlp->BIDR.B.DIR = (uint8_t)ldp->config->nofilter->direction;
            linflexlp->BIDR.B.ID = ldp->config->nofilter->value;
            if (ldp->config->nofilter->direction == LIN_DIRECTION_RECEIVE)
            {
                linflexlp->LINCR2.B.DDRQ = 0;
            }
            else
            {
                ld_txi(ldp, ldp->tx_buf, ldp->tx_len);
                linflexlp->LINCR2.B.DTRQ = 1;
            }
        }
        linflexlp->LINSR.B.HRF = 1;
    }

    /* Retrieve message data length */
    len = (uint16_t)linflexlp->BIDR.B.DFL + 1U;

    if (ldp->config->mode == LIN_MODE_MASTER)
    {
        /* Master receive */
        /* Disable receive interrupt */
        linflexlp->LINIER.B.DRIE = 0;

        /* Check the size of the data buffer */
        if (ldp->rx_len < len)
        {
            len = ldp->rx_len;
        }

        /* Set returned data length */
        ldp->rx_len = len;
        if (ldp->config->dma_enable == (uint8_t)1)
        {
            temp = (int32_t)ldp->rx_len;
            temp = - temp;
            EdmaChannelSetup_C(0, (vuint32_t)&LINFLEX_0.BDRL, (vuint32_t)ldp->rx_buf, 4, 4, 2, 2, \
                              (uint32_t)ldp->rx_len, 1, temp, (int32_t)ldp->rx_len, 0);
            EDMA.TCD[0].START = 1; /* PRQA S 0662*/  
            while (EDMA.TCD[0].DONE == (uint8_t)0)/* PRQA S 0662*/  
            {}
        }
        else
        {
            ld_rxi(ldp, ldp->rx_buf, ldp->rx_len);
        }
        linflexlp->LINSR.B.DRF = 1;
    }
    else if ((ldp->config->mode == LIN_MODE_SLAVE) && (linflexlp->LINSR.B.DRF == (uint8_t)1))
    {
        if (ldp->config->dma_enable == (uint8_t)1)
        {
            temp = (int32_t)ldp->rx_len;
            temp = - temp;
            EdmaChannelSetup_C(0, (vuint32_t)&LINFLEX_0.BDRL, (vuint32_t)ldp->rx_buf, 4, 4, 2, 2, \
                             (uint32_t)ldp->rx_len, 1, temp, (int32_t)ldp->rx_len, 0);
            EDMA.TCD[0].START = 1;                /* PRQA S 0662*/  
            while (EDMA.TCD[0].DONE == (uint8_t)0)/* PRQA S 0662*/  
            {
            }
        }
        else
        {
            ld_rxi(ldp, ldp->rx_buf, ldp->rx_len);
        }
        linflexlp->LINSR.B.DRF = 1;
    }
    else
    {
        /** No code **/
    }
    CCFC20xx_LIN_RX_DONE(ldp);
}

/*******************************************************************************
 * @brief      LINFlex_ERR_IRQHandler
 * @param[in]  uint32_t ildp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void LINFlex_ERR_IRQHandler(uint32_t ildp)
{
    static uint32_t flagcount;
    LinDriver *ldp = (LinDriver *)(ildp);
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    if ((1u == linflexlp->LINESR.B.OCF) && (flagcount < 5u))
    {
        linflexlp->LINESR.B.OCF = 1;
        CCFC20xx_LIN_RX_DONE(ldp);
        flagcount++;
    }
    else
    {
    }
}

/*******************************************************************************
 * @brief      This function shall be used the GPIO init.
 * @param[in]  LinDriver *ldp, lin_gpio_select_t IO
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Gpio_Init(const LinDriver *ldp, lin_gpio_select_t IO)
{
    if (ldp == &LD1)
    {
        if (IO == LIN_GPIO_DEFAULT)
        {
            SIU.PSMI[62].B.PADSEL = 0;
            SIU.PCR[18].R = 0x0400;             /* CCFC20xxBC: Configure port PB[2] as LIN_0 TX */
            SIU.PCR[19].R = 0x0103;             /* CCFC20xxBC: Configure port PB[3] as LIN_0 RX */
        }
        if (IO == LIN_GPIO_MUX)
        {
            SIU.PSMI[62].B.PADSEL = 1;
            SIU.PCR[16].R = 0x0C00;             /* CCFC20xxBC: Configure port PB[0] as LIN_0 TX */
            SIU.PCR[17].R = 0x0103;             /* CCFC20xxBC: Configure port PB[1] as LIN_0 RX */
        }
    }
    if (ldp == &LD2)
    {
        SIU.PCR[38].R = 0x0400;             /* CCFC20xxBC: Configure port PC[6] as LIN_1 TX */
        SIU.PCR[39].R = 0x0103;             /* CCFC20xxBC: Configure port PC[7] as LIN_1 RX */
    }
    if (ldp == &LD3)
    {
        if (IO == LIN_GPIO_DEFAULT)
        {
            SIU.PSMI[58].B.PADSEL = 0;
            SIU.PCR[40].R = 0x0400;             /* CCFC20xxBC: Configure port PC[8] as LIN_2 TX */
            SIU.PCR[41].R = 0x0103;             /* CCFC20xxBC: Configure port PC[9] as LIN_2 RX */
        }
        if (IO == LIN_GPIO_MUX)
        {
            SIU.PSMI[58].B.PADSEL = 1;
            SIU.PCR[10].R = 0x0C00;             /* CCFC20xxBC: Configure port PA[10] as LIN_2 TX */
            SIU.PCR[11].R = 0x0103;             /* CCFC20xxBC: Configure port PA[11] as LIN_2 RX */
        }
    }
    if (ldp == &LD4)
    {
        if (IO == LIN_GPIO_DEFAULT)
        {
            SIU.PSMI[31].B.PADSEL = 0;
            SIU.PCR[7].R = 0x0800;               /* CCFC20xxBC: Configure port PA[7] as LIN_3 TX */
            SIU.PCR[8].R = 0x0103;              /* CCFC20xxBC: Configure port PA[8] as LIN_3 RX */
        }
        if (IO == LIN_GPIO_MUX)
        {
            SIU.PSMI[31].B.PADSEL = 1;
            SIU.PCR[74].R = 0x0400;             /* CCFC20xxBC: Configure port PE[10] as LIN_3 TX */
            SIU.PCR[75].R = 0x0103;             /* CCFC20xxBC: Configure port PE[11] as LIN_3 RX */
        }
    }
    if (ldp == &LD5)
    {
        if (IO == LIN_GPIO_DEFAULT)
        {
            SIU.PSMI[59].B.PADSEL = 0;
            SIU.PCR[5].R = 0x0800;              /* CCFC20xxBC: Configure port PA[5] as LIN_4 TX */
            SIU.PCR[6].R = 0x0103;              /* CCFC20xxBC: Configure port PA[6] as LIN_4 RX */
        }
        if (IO == LIN_GPIO_MUX)
        {
            SIU.PSMI[59].B.PADSEL = 1;
            SIU.PCR[90].R = 0x0800;             /* CCFC20xxBC: Configure port PF[10] as LIN_4 TX */
            SIU.PCR[91].R = 0x0103;             /* CCFC20xxBC: Configure port PF[11] as LIN_4 RX */
        }
    }
    if (ldp == &LD6)
    {
        if (IO == LIN_GPIO_DEFAULT)
        {
            SIU.PSMI[60].B.PADSEL = 0;
            SIU.PCR[3].R = 0x0800;              /* CCFC20xxBC: Configure port PA[3] as LIN_5 TX */
            SIU.PCR[4].R = 0x0103;              /* CCFC20xxBC: Configure port PA[4] as LIN_5 RX */
        }
        if (IO == LIN_GPIO_MUX)
        {
            SIU.PSMI[60].B.PADSEL = 1;
            SIU.PCR[92].R = 0x0800;             /* CCFC20xxBC: Configure port PF[12] as LIN_5 TX */
            SIU.PCR[93].R = 0x0103;             /* CCFC20xxBC: Configure port PF[13] as LIN_5 RX */
        }
    }
    if (ldp == &LD7)
    {
        SIU.PCR[102].R = 0x0800;                /* CCFC20xxBC: Configure port PG[6] as LIN_6 TX */
        SIU.PCR[103].R = 0x0103;                /* CCFC20xxBC: Configure port PG[7] as LIN_6 RX */
    }
    if (ldp == &LD8)
    {
        SIU.PCR[104].R = 0x0800;                /* CCFC20xxBC: Configure port PG[8] as LIN_7 TX */
        SIU.PCR[105].R = 0x0103;                /* CCFC20xxBC: Configure port PG[9] as LIN_7 RX */
    }
}

/*******************************************************************************
 * @brief      This function shall be used the LIN mode INIT.
 * @param[in]  const LinDriver *ldp, const LinConfig *config
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Lld_Init(const LinDriver *ldp, const LinConfig *config)
{
    if (ldp == &LD1)
    {
        LD1.linflexlp = &CCFC20xx_LINFLEX0L;
        LD1.linflexhp = &CCFC20xx_LINFLEX0H;
        LD1.config = config;
        LinflexD1.device = (uint32_t)&LD1;
        LinflexD1.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD1.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD1.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD2)
    {
        LD2.linflexlp = &CCFC20xx_LINFLEX1L;
        LD2.linflexhp = &CCFC20xx_LINFLEX1H;
        LD2.config = config;
        LinflexD2.device = (uint32_t)&LD2;
        LinflexD2.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD2.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD2.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD3)
    {
        LD3.linflexlp = &CCFC20xx_LINFLEX2L;
        LD3.config = config;
        LinflexD3.device = (uint32_t)&LD3;
        LinflexD3.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD3.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD3.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD4)
    {
        LD4.linflexlp = &CCFC20xx_LINFLEX3L;
        LD4.config = config;
        LinflexD4.device = (uint32_t)&LD4;
        LinflexD4.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD4.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD4.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD5)
    {
        LD5.linflexlp = &CCFC20xx_LINFLEX4L;
        LD5.config = config;
        LinflexD5.device = (uint32_t)&LD5;
        LinflexD5.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD5.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD5.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD6)
    {
        LD6.linflexlp = &CCFC20xx_LINFLEX5L;
        LD6.config = config;
        LinflexD6.device = (uint32_t)&LD6;
        LinflexD6.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD6.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD6.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD7)
    {
        LD7.linflexlp = &CCFC20xx_LINFLEX6L;
        LD7.config = config;
        LinflexD7.device = (uint32_t)&LD7;
        LinflexD7.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD7.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD7.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else if (ldp == &LD8)
    {
        LD8.linflexlp = &CCFC20xx_LINFLEX7L;
        LD8.config = config;
        LinflexD8.device = (uint32_t)&LD8;
        LinflexD8.rxi_lincallback = LINFlex_RXI_IRQHandler;
        LinflexD8.txi_lincallback = LINFlex_TXI_IRQHandler;
        LinflexD8.err_lincallback = LINFlex_ERR_IRQHandler;
    }
    else
    {
        /** No code **/
    }
}

/*******************************************************************************
 * @brief      This function shall be used the LIN mode DEINIT.
 * @param[in]  LinDriver *ldp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Lld_DeInit(const LinDriver *ldp)
{
    if (ldp == &LD1)
    {
        LD1.linflexlp = NULL;
        LD1.linflexhp = NULL;
        LD1.config = NULL;
        LinflexD1.device = 0;
        LinflexD1.rxi_lincallback = NULL;
        LinflexD1.txi_lincallback = NULL;
        LinflexD1.err_lincallback = NULL;
    }
    else if (ldp == &LD2)
    {
        LD2.linflexlp = NULL;
        LD2.linflexhp = NULL;
        LD2.config = NULL;
        LinflexD2.device = 0;
        LinflexD2.rxi_lincallback = NULL;
        LinflexD2.txi_lincallback = NULL;
        LinflexD2.err_lincallback = NULL;
    }
    else if (ldp == &LD3)
    {
        LD3.linflexlp = NULL;
        LD3.config = NULL;
        LinflexD3.device = 0;
        LinflexD3.rxi_lincallback = NULL;
        LinflexD3.txi_lincallback = NULL;
        LinflexD3.err_lincallback = NULL;
    }
    else if (ldp == &LD4)
    {
        LD4.linflexlp = NULL;
        LD4.config = NULL;
        LinflexD4.device = 0;
        LinflexD4.rxi_lincallback = NULL;
        LinflexD4.txi_lincallback = NULL;
        LinflexD4.err_lincallback = NULL;
    }
    else if (ldp == &LD5)
    {
        LD5.linflexlp = NULL;
        LD5.config = NULL;
        LinflexD5.device = 0;
        LinflexD5.rxi_lincallback = NULL;
        LinflexD5.txi_lincallback = NULL;
        LinflexD5.err_lincallback = NULL;
    }
    else if (ldp == &LD6)
    {
        LD6.linflexlp = NULL;
        LD6.config = NULL;
        LinflexD6.device = 0;
        LinflexD6.rxi_lincallback = NULL;
        LinflexD6.txi_lincallback = NULL;
        LinflexD6.err_lincallback = NULL;
    }
    else if (ldp == &LD7)
    {
        LD7.linflexlp = NULL;
        LD7.config = NULL;
        LinflexD7.device = 0;
        LinflexD7.rxi_lincallback = NULL;
        LinflexD7.txi_lincallback = NULL;
        LinflexD7.err_lincallback = NULL;
    }
    else if (ldp == &LD8)
    {
        LD8.linflexlp = NULL;
        LD8.config = NULL;
        LinflexD8.device = 0;
        LinflexD8.rxi_lincallback = NULL;
        LinflexD8.txi_lincallback = NULL;
        LinflexD8.err_lincallback = NULL;
    }
    else
    {
        /** No code **/
    }
}

/*******************************************************************************
 * @brief      This function shall be the IrqIsr Enable.
 * @param[in]  LinDriver *ldp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Init_IrqIsrEnable(const LinDriver *ldp)
{
    if (ldp == &LD1)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX0_TXI_IRQ_HANDLER, (uint16_t)LINFLEX0_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX0_RXI_IRQ_HANDLER, (uint16_t)LINFLEX0_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX0_ERR_IRQ_HANDLER, (uint16_t)LINFLEX0_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD2)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX1_TXI_IRQ_HANDLER, (uint16_t)LINFLEX1_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX1_RXI_IRQ_HANDLER, (uint16_t)LINFLEX1_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX1_ERR_IRQ_HANDLER, (uint16_t)LINFLEX1_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD3)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX2_TXI_IRQ_HANDLER, (uint16_t)LINFLEX2_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX2_RXI_IRQ_HANDLER, (uint16_t)LINFLEX2_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX2_ERR_IRQ_HANDLER, (uint16_t)LINFLEX2_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD4)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX3_TXI_IRQ_HANDLER, (uint16_t)LINFLEX3_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX3_RXI_IRQ_HANDLER, (uint16_t)LINFLEX3_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX3_ERR_IRQ_HANDLER, (uint16_t)LINFLEX3_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD5)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX4_TXI_IRQ_HANDLER, (uint16_t)LINFLEX4_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX4_RXI_IRQ_HANDLER, (uint16_t)LINFLEX4_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX4_ERR_IRQ_HANDLER, (uint16_t)LINFLEX4_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD6)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX5_TXI_IRQ_HANDLER, (uint16_t)LINFLEX5_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX5_RXI_IRQ_HANDLER, (uint16_t)LINFLEX5_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX5_ERR_IRQ_HANDLER, (uint16_t)LINFLEX5_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD7)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX6_TXI_IRQ_HANDLER, (uint16_t)LINFLEX6_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX6_RXI_IRQ_HANDLER, (uint16_t)LINFLEX6_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX6_ERR_IRQ_HANDLER, (uint16_t)LINFLEX6_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else if (ldp == &LD8)
    {
        INTC_InstallINTCInterruptHandler(LINFLEX7_TXI_IRQ_HANDLER, (uint16_t)LINFLEX7_TXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX7_RXI_IRQ_HANDLER, (uint16_t)LINFLEX7_RXI_IRQn, (uint8_t)PSR_PRI_8);
        INTC_InstallINTCInterruptHandler(LINFLEX7_ERR_IRQ_HANDLER, (uint16_t)LINFLEX7_ERR_IRQn, (uint8_t)PSR_PRI_8);
    }
    else
    {
        /** No code **/
    }
}

/*******************************************************************************
 * @brief      This function shall be the Master receive.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint16_t Lin_Master_Receive(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    uint8_t temp = msg_len;

    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    Linflex_Start(ldp);

    if ((temp == 0U) || (temp > 8U))
    {
        return 1;
    }

    CCFC20xx_LIN_RX_IN_PROGRESS(ldp);

    /* Prepare buffer for receiving data */
    ldp->rx_buf = buffer;
    ldp->rx_len = msg_len;

    /* Prepare message header */
    linflexlp->BIDR.R = 0;
    linflexlp->BIDR.B.ID  = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.DFL = msg_len - 1u; /* Configure DFL in BIDR */
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_RECEIVE;

    /* Enable Data Receive interrupt */
    linflexlp->LINIER.B.DRIE = 1;

    linflexlp->LINIER.B.OCIE = 1;

    /* Trigger Header transmission*/
    linflexlp->LINCR2.B.HTRQ = 1;

    CCFC20xx_LIN_WAIT_FOR_RX_COMPLETION(ldp);

    /* rx_len could have been changed at interrupt time */
    return ldp->rx_len;
}

/*******************************************************************************
 * @brief      This function shall be the master transmit.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Master_Transmit(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    Linflex_Start(ldp);

    if ((msg_len == 0U) || (msg_len > 8U))
    {
        return;
    }

    CCFC20xx_LIN_TX_IN_PROGRESS(ldp);

    /* Save message parameters */
    ldp->tx_id_msg = idMessage;
    ldp->tx_buf = buffer;
    ldp->tx_len = msg_len;

    /* Set Header */
    linflexlp->BIDR.R = 0;
    linflexlp->BIDR.B.ID = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.DFL = msg_len - 1U; /* Configure DFL in BIDR */
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_TRANSMIT;

    ld_txi(ldp, buffer, msg_len);

    /* Enable transmit interrupt */
    linflexlp->LINIER.B.DTIE = 1;

    /* Trigger Header transmission*/
    linflexlp->LINCR2.B.HTRQ = 1;

    if ((ldp->config->api_mode == CCFC20xx_LIN_API_MODE_SYNCHRONOUS) || (ldp->config->api_mode == CCFC20xx_LIN_API_MODE_BUFFERED_IO))
    {
        while (ldp->tx_busy == CCFC20xx_LIN_TX_READY)
        {
        }
    }
}

/*******************************************************************************
 * @brief      This function shall be the slave receive.
 * @param[in]  LinDriver *ldp, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint16_t Lin_Slave_Receive(LinDriver *ldp, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    Linflex_Start(ldp);

    if ((msg_len == 0U) || (msg_len > 8U))
    {
        return 0;
    }

    CCFC20xx_LIN_RX_IN_PROGRESS(ldp);

    /* Prepare buffer for receiving data */
    ldp->rx_buf = buffer;
    ldp->rx_len = msg_len;

    /* Enable Data Receive interrupt */
    linflexlp->LINIER.B.DRIE = 1;

    CCFC20xx_LIN_WAIT_FOR_RX_COMPLETION(ldp);

    return ldp->rx_len;
}

/*******************************************************************************
 * @brief      This function shall be the slave transmit.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Slave_Transmit(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    Linflex_Start(ldp);

    if ((msg_len == 0U) || (msg_len > 8U))
    {
        return;
    }

    CCFC20xx_LIN_TX_IN_PROGRESS(ldp);

    /* Save message parameters */
    ldp->tx_id_msg = idMessage;
    ldp->tx_buf = buffer;
    ldp->tx_len = msg_len;
    linflexlp->LINIER.B.DTIE = 1;

    if ((ldp->config->api_mode == CCFC20xx_LIN_API_MODE_SYNCHRONOUS) || (ldp->config->api_mode == CCFC20xx_LIN_API_MODE_BUFFERED_IO))
    {
        while (ldp->tx_busy == CCFC20xx_LIN_TX_BUSY)
        {
        }
    }
}

/*******************************************************************************
 * @brief      This function shall be the polling master transmit.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Master_Polling_Transmit(const LinDriver *ldp, uint8_t idMessage, const uint8_t *buffer, uint8_t buf_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)LIN_MODE_MASTER;  /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;                          /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;                          /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 0;

    linflexlp->LINCR2.B.IOBE = 0;                          /* Bit Error does not reset LIN state machine */

    linflexlp->LINTCSR.B.LTOM = 0;                         /* LIN timeout mode for 8 - bit counter */

    linflexlp->LINTCSR.B.IOT  = 0;                         /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;                         /* Time - out counter enable - OCF flag is set if \
                                                              an output compare event occurs */
    linflexlp->LINSR.R = 0xFFFF;                           /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;                                 /* LIN Interrupts disabled.     */

    /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F = LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M = LIN_DIV_M;

    linflexlp->LINCR1.B.INIT = 0;

    /* Prepare message header */
    linflexlp->BIDR.R = 0;                      /** clear register **/
    linflexlp->BIDR.B.ID = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DFL = (uint8_t)(((uint32_t)buf_len - 1U) & CCFC20xx_BIDR_DFL_MASK);
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_TRANSMIT;

    linflexlp->LINCR2.B.HTRQ = 1;      /* Request header transmission */

    ld_txi(ldp, buffer, 8);

    linflexlp->LINCR2.B.DTRQ = 1;      /* Request data  transmission */

    while (linflexlp->LINSR.B.DTF == (uint8_t)0)
    {
    }
    linflexlp->LINSR.B.DTF = 1;
}

/*******************************************************************************
 * @brief      This function shall be the polling master receive.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Master_Polling_Receive(const LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t buf_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)LIN_MODE_MASTER;    /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;                          /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;                          /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 0;

    linflexlp->LINCR2.B.IOBE = 0;                          /* Bit Error does not reset LIN state machine */

    linflexlp->LINTCSR.B.LTOM = 0;                         /* LIN timeout mode for 8 - bit counter */

    linflexlp->LINTCSR.B.IOT  = 0;                         /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;
    linflexlp->LINSR.R = 0xFFFF;                           /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;                               /* LIN Interrupts disabled.     */

    /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F = LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M = LIN_DIV_M;

    linflexlp->LINCR1.B.INIT = 0;

    /* Prepare message header */
    linflexlp->BIDR.R = 0;                      /** clear register **/
    linflexlp->BIDR.B.ID = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DFL = (uint8_t)(((uint32_t)buf_len - 1U) & CCFC20xx_BIDR_DFL_MASK);
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_RECEIVE;

    linflexlp->LINCR2.B.HTRQ = 1;      /* Request header transmission */

    while (linflexlp->LINSR.B.DRF == (uint8_t)0)
    {
    }
    linflexlp->LINSR.B.DRF = 1;
    ld_rxi(ldp, buffer, buf_len);
}

/*******************************************************************************
 * @brief      This function shall be the polling slave receive.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Slave_Polling_Receive(const LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t buf_len)
{
    uint8_t i = 0;
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)LIN_MODE_SLAVE;  /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;                          /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;                          /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 1;

    linflexlp->LINCR2.B.IOBE = 0;                          /* Bit Error does not reset LIN state machine */

    linflexlp->LINTCSR.B.LTOM = 0;                         /* LIN timeout mode for 8 - bit counter */

    linflexlp->LINTCSR.B.IOT  = 0;                         /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;
    linflexlp->LINSR.R = 0xFFFF;                           /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;                                 /* LIN Interrupts disabled.     */

    /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F = LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M = LIN_DIV_M;

    if ((ldp->config->filters != NULL) && (ldp->config->nofilter == NULL))
    {
        while (i < LIN_NUM_FILTERS)
        {
            LinFilter const *p = ldp->config->filters[i];
            if (p != NULL)
            {
                CCFC20xx_linflex_set_filter(ldp, i, p);
                if (p->mode == LIN_MASK_MODE)
                { /* The filter 2n is in Mask mode, then skip the next one because the */
                    i += 1U;                        /* Mask value has been already set in filter 2n + 1.                   */
                }
            }
            i += 1U;
        }
        linflexlp->LINCR1.B.BF = 0;
    }
    linflexlp->LINCR1.B.INIT = 0;
    if ((ldp->config->filters == NULL) && (ldp->config->nofilter != NULL))
    {
        while (linflexlp->LINSR.B.HRF == (uint8_t)0)
        {
        }
        linflexlp->BIDR.B.CCS = (uint8_t)LIN_ENHANCED_CHECKSUM;
        linflexlp->BIDR.B.DFL = (uint8_t)((uint8_t)buf_len - 1u);
        linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_RECEIVE;
        linflexlp->BIDR.B.ID = idMessage;
    }
    while (linflexlp->LINSR.B.DRF == (uint8_t)0)
    {
    }
    linflexlp->LINSR.B.DRF = 1;

    ld_rxi(ldp, buffer, buf_len);
}

/*******************************************************************************
 * @brief      This function shall be the polling slave transmit.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Slave_Polling_Transmit(const LinDriver *ldp, uint8_t idMessage, const uint8_t *buffer, uint8_t buf_len)
{
    uint8_t i = 0;
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)LIN_MODE_SLAVE;  /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;                          /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;                          /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 1;

    linflexlp->LINCR2.B.IOBE = 0;                          /* Bit Error does not reset LIN state machine */

    linflexlp->LINTCSR.B.LTOM = 0;                         /* LIN timeout mode for 8 - bit counter */

    linflexlp->LINTCSR.B.IOT  = 0;                         /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;
    linflexlp->LINSR.R = 0xFFFF;                           /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;                                 /* LIN Interrupts disabled.     */

    /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F = LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M = LIN_DIV_M;
 
    if ((ldp->config->filters != NULL) && (ldp->config->nofilter == NULL))
    {
        while (i < LIN_NUM_FILTERS)
        {
            LinFilter const *p = ldp->config->filters[i];
            if (p != NULL)
            {
                CCFC20xx_linflex_set_filter(ldp, i, p);
                if (p->mode == LIN_MASK_MODE)
                { /* The filter 2n is in Mask mode, then skip the next one because the */
                    i += 1U;                        /* Mask value has been already set in filter 2n + 1.                   */
                }
            }
            i += 1U;
        }
        linflexlp->LINCR1.B.BF = 0;
    }
    linflexlp->LINCR1.B.INIT = 0;

    while (linflexlp->LINSR.B.HRF == (uint8_t)0)
    {
    }
    if ((ldp->config->filters == NULL) && (ldp->config->nofilter != NULL))
    {
        linflexlp->BIDR.B.CCS = (uint8_t)LIN_ENHANCED_CHECKSUM;
        linflexlp->BIDR.B.DFL = (uint8_t)((uint8_t)buf_len - 1u);
        linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_TRANSMIT;
        linflexlp->BIDR.B.ID = idMessage;
    }

    ld_txi(ldp, buffer, buf_len);

    linflexlp->LINCR2.B.DTRQ = 1;
    while (linflexlp->LINSR.B.DTF == (uint8_t)0)
    {
    }
    linflexlp->LINSR.B.DTF = 1;
}

/*******************************************************************************
 * @brief      This function shall be the master transmit by DMA.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Master_Transmit_DMA(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    volatile struct CCFC20xxbc_linflexh *linflexhp = ldp->linflexhp;

    uint32_t u32_txBuffdma[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000000};
    uint32_t temp = 0;
    int8_t temp_value = 0;
    uint8_t temp_len = 0u;

    Linflex_Start(ldp);

    if ((msg_len == 0U) || (msg_len > 8U))
    {
        return;
    }

    CCFC20xx_LIN_TX_IN_PROGRESS(ldp);

    /* Save message parameters */
    ldp->tx_id_msg = idMessage;
    ldp->tx_buf = buffer;
    ldp->tx_len = msg_len;

    temp = (uint32_t)((uint32_t)msg_len - 1u);
    temp = ((temp) << 10u);
    temp = (uint32_t)idMessage |temp;
    temp = (uint32_t)0x00000200|(uint32_t)temp;
    u32_txBuffdma[0] = 0x00000800;                 /** CR2 register **/
    u32_txBuffdma[1] = (uint32_t)temp;        /** BIDR register **/

    Lin_Txi_DMA(&u32_txBuffdma[2], buffer, msg_len); /** put buffer into register **/

    DMAMUX_ChConfigEn(0, 34);                        /** DMA_MUX Source #34 : LIN TX    **/

    EDMA.CPR[0].R = 0x0;                           /** Channel 0 priority: group priority = 0, channel priority = 0 **/
    EDMA.SERQR.R = 0;                              /** Enable EDMA channel 0 **/
    EDMA.SSBR.R = 0;                               /** Set channel 0 START bit to initiate first minor loop transfer **/
    
    temp_len = msg_len + 8u;
    temp_value = (int8_t)(msg_len);
    temp_value = -temp_value;
    EdmaChannelSetup_C(0u, (vuint32_t)u32_txBuffdma, (vuint32_t)&LINFLEX_0.LINCR2, 4u, 4u, 2u, 2u, \
                      (uint8_t)(temp_len),1 , temp_value,  (int32_t)(temp_len), 0u);

    linflexhp->DMATXE.B.DTE = 1;
    linflexlp->LINIER.B.DTIE = 1;

    EDMA.TCD[0].START = 1;           /* PRQA S 0662*/                /** Initialize status flags **/

    while (EDMA.TCD[0].DONE == (uint8_t)0) /* PRQA S 0662*/  
    {}

    linflexlp->LINCR2.B.HTRQ = 1;                   /** Trigger Header transmission **/

    if (ldp -> config -> api_mode == CCFC20xx_LIN_API_MODE_SYNCHRONOUS)
    {
        while (ldp->tx_busy == CCFC20xx_LIN_TX_BUSY)
        {}
    }
}

/*******************************************************************************
 * @brief      This function shall be the master receive by DMA.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint16_t Lin_Master_Receive_DMA(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    /** Used the FlexLinD **/
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    volatile struct CCFC20xxbc_linflexh *linflexhp = ldp->linflexhp;

    Linflex_Start(ldp);

    if ((0U == msg_len) || (msg_len > 8U))
    {
        return 0;
    }

    CCFC20xx_LIN_RX_IN_PROGRESS(ldp);

    /* Prepare message header */
    linflexlp->BIDR.R = 0;
    linflexlp->BIDR.B.ID  = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.DFL = msg_len - 1U; /* Configure DFL in BIDR */ /* 2985 */
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_RECEIVE;

    /* Prepare buffer for receiving data */
    ldp->rx_buf = buffer;
    ldp->rx_len = msg_len;

    /**     DMA_MUX    **/
    DMAMUX_ChConfigEn(0, 33);                        

    EDMA.CPR[0].R = 0x0;               /** Channel 0 priority: group priority = 0, channel priority = 0 **/
    EDMA.SERQR.R = 0;                  /** Enable EDMA channel 0 **/
    EDMA.SSBR.R = 0;                   /** Set channel 0 START bit to initiate first minor loop transfer **/

    linflexhp->DMARXE.B.DRE = 1;
    linflexlp->LINCR2.B.HTRQ = 1;

    CCFC20xx_LIN_WAIT_FOR_RX_COMPLETION(ldp);
    return ldp->rx_len;
}

/*******************************************************************************
 * @brief      This function shall be the master receive by DMA.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Slave_Transmit_DMA(LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    volatile struct CCFC20xxbc_linflexh *linflexhp = ldp->linflexhp;

    Linflex_Start(ldp);

    if ((0U == msg_len) || (msg_len > 8U))
    {
        return ;
    }

    CCFC20xx_LIN_TX_IN_PROGRESS(ldp);

    ldp->tx_id_msg = idMessage;
    ldp->tx_buf = buffer;
    ldp->tx_len = msg_len;

    DMAMUX_ChConfigEn(0, 34);                        /** DMA_MUX Source #34 : LIN TX    **/

    EDMA.CPR[0].R = 0x0;                           /** Channel 0 priorites: group priority = 0, channel priority = 0 **/
    EDMA.SERQR.R = 0;                              /** Enable EDMA channel 0 **/
    EDMA.SSBR.R = 0;                               /** Set channel 0 START bit to initiate first minor loop transfer **/

    linflexlp->LINIER.B.DTIE = 1;

    linflexhp->DMATXE.B.DTE = 1;
    linflexhp->DMARXE.B.DRE = 1;
     
    while (EDMA.TCD[0].DONE == (uint8_t)0)  /* PRQA S 0662*/  
    {}
    
    if ((ldp->config->api_mode == CCFC20xx_LIN_API_MODE_SYNCHRONOUS) || (ldp->config->api_mode == CCFC20xx_LIN_API_MODE_BUFFERED_IO))
    {
        while (ldp->tx_busy == CCFC20xx_LIN_TX_BUSY)
        {
        }
    }
}

/*******************************************************************************
 * @brief      This function shall be the master receive by DMA.
 * @param[in]  LinDriver *ldp, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint16_t Lin_Slave_Receive_DMA(LinDriver *ldp, uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexh *linflexhp = ldp->linflexhp;

    Linflex_Start(ldp);

    if ((0U == msg_len) || (msg_len > 8U))
    {
        return 1;
    }

    CCFC20xx_LIN_RX_IN_PROGRESS(ldp);
    /* Prepare buffer for receiving data */
    ldp->rx_buf = buffer;
    ldp->rx_len = msg_len;

    DMAMUX_ChConfigEn(0, 33);                        /** DMA_MUX Source #34 : LIN TX    **/

    EDMA.CPR[0].R = 0x0;               /** Channel 0 priority: group priority = 0, channel priority = 0 **/
    EDMA.SERQR.R = 0;                  /** Enable EDMA channel 0 **/
    EDMA.SSBR.R = 0;                   /** Set channel 0 START bit to initiate first minor loop transfer **/

    linflexhp->DMARXE.B.DRE = 1;

    CCFC20xx_LIN_WAIT_FOR_RX_COMPLETION(ldp);

    return ldp->rx_len;
}

/*******************************************************************************
 * @brief      This function shall be used enter the low power mode.
 * @param[in]  LinDriver *ldp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_LLD_Lowper_enter(const LinDriver *ldp)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    linflexlp->LINCR1.B.INIT = 1;               /* Enter in Initialization Mode  */
    linflexlp->LINCR1.B.SLEEP = 1;
    linflexlp->LINCR1.B.INIT = 0;
}

/*******************************************************************************
 * @brief      This function shall be used exit the low power mode.
 * @param[in]  LinDriver *ldp
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_LLD_Lowper_exit(const LinDriver * ldp)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = ldp->linflexlp;
    linflexlp->LINCR1.B.INIT = 1;
    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 0;
}

/*******************************************************************************
 * @brief      This function shall be the used transmit the extend frame by polling.
 * @param[in]  LinDriver *lind, uint8_t idMessage, uint8_t *buffer, uint8_t msg_len
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void Lin_Master_Polling_Transmit_ExtendFrame(const LinDriver *lind, uint8_t idMessage, const uint8_t *buffer, uint8_t msg_len)
{
    volatile struct CCFC20xxbc_linflexl *linflexlp = lind->linflexlp;
    uint8_t i;

    linflexlp->LINCR1.B.SLEEP = 0;                         /* exit sleep mode, Enters the configuration mode */
    linflexlp->LINCR1.B.INIT = 1;                          /* Enter in Initialization Mode  */

    while (0x1000U != (linflexlp->LINSR.R & 0xF000U))
    {
    }
    linflexlp->LINCR1.B.MME = (uint8_t)LIN_MODE_MASTER;  /* Select Master/Slave mode */
    linflexlp->LINCR1.B.MBL = 3U;                          /* 13 - bit break */
    linflexlp->LINCR1.B.LASE = 0;                          /* Auto synchronization disabled */
    linflexlp->LINCR1.B.BF = 0;
    linflexlp->LINCR2.B.IOBE = 0;                          /* Bit Error does not reset LIN state machine */

    linflexlp->LINTCSR.B.LTOM = 0;                         /* LIN timeout mode for 8 - bit counter */
    linflexlp->LINTCSR.B.IOT  = 0;                         /* LIN state machine does not reset to Idle on timeout */
    linflexlp->LINTCSR.B.TOCE = 0;
    linflexlp->LINSR.R = 0xFFFF;                           /* Clearing LINSR register. */
    linflexlp->LINIER.R = 0;                               /* LIN Interrupts disabled.     */

     /* Set the LIN baud Rate */
    linflexlp->LINFBRR.B.DIV_F = LIN_DIV_F;
    linflexlp->LINIBRR.B.DIV_M = LIN_DIV_M;

    linflexlp->LINCR1.B.INIT = 0;

    /* Prepare message header */
    linflexlp->BIDR.R = 0;             /** clear register **/
    linflexlp->BIDR.B.ID = idMessage & CCFC20xx_BIDR_ID_MASK;
    linflexlp->BIDR.B.CCS = 0;
    linflexlp->BIDR.B.DFL = (uint8_t)(((uint32_t)msg_len - 1U) & CCFC20xx_BIDR_DFL_MASK); /* Configure DFL in BIDR */
    linflexlp->BIDR.B.DIR = (uint8_t)LIN_DIRECTION_TRANSMIT;

    linflexlp->LINCR2.B.HTRQ = 1;      /* Request header transmission */

    ld_txi(lind, buffer, 8);

    linflexlp->LINCR2.B.DTRQ = 1;      /* Request data transmission */

    for (i = 8; i < msg_len; i = i + 8u)
    {
        while (linflexlp->LINSR.B.DBEF == (uint8_t)0)
        {}
        linflexlp->LINSR.B.DBEF = 1;
        ld_txi(lind, buffer + i, 8);
    }

    while (linflexlp->LINSR.B.DTF == (uint8_t)0)
    {}
    linflexlp->LINSR.B.DTF = 1;
}
